package com.gis.utils;

import com.gis.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Component
public class PythonUtil {
    @Value("${python.path}")
    private String pythonPath;

    /**
     * 空间分析请求
     * @param data
     * @return
     */
    public boolean runSpatialAnalysis(List<List<Float>> data) {
        try {
            // 1 组装命令行
            String geojsonPath = "tif/map.geojson";
            String tifPath = "tif/output.tif";
            List<String> dataPoints = new ArrayList<>();
            for (List<Float> value : data) {
                // 将转换为逗号分隔的字符串
                String joinedValues = String.join(",", value.stream().map(Object::toString).collect(Collectors.toList()));
                dataPoints.add(joinedValues);
            }
            String combinedDataPoints = String.join(";", dataPoints);
            // 2 执行脚本
            File workingDirectory = new File(pythonPath);
            ProcessBuilder processBuilder = new ProcessBuilder(
                    "bash",
                    "run_geojsonToTif.sh",
                    "--geojson", geojsonPath,
                    "--tif", tifPath,
                    "--data_points", combinedDataPoints
            );
            processBuilder.directory(workingDirectory);
            // 合并错误流和输出流
            processBuilder.redirectErrorStream(true);
            // 启动进程
            Process process = processBuilder.start();
            // 读取脚本的输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            String lastLine = null;
            while ((line = reader.readLine()) != null) {
                lastLine = line;
//                log.info(lastLine);
            }
            // 等待进程结束，并获取退出状态码
            int exitCode = process.waitFor();
            if (exitCode == 0 && lastLine.equals("success")) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("时空分析失败", e);
        }
    }

    public boolean predict(List<Float> data, String type, String param, String model) {
        try {
            // 1 组装命令行
            if(model==null)
                model = "Seq2Seq";
            String modelName = type+"_"+param+"_"+model;
            List<String> dataPoints = new ArrayList<>();
            for (Float value : data) {
                String joinedValues = String.join(" ", value.toString());
            }
            String combinedDataPoints = String.join(";", dataPoints);
            // 2 执行脚本
            File workingDirectory = new File(pythonPath);
            ProcessBuilder processBuilder = new ProcessBuilder(
                    "bash",
                    "run_geojsonToTif.sh",
                    "-m", modelName,
                    " ", combinedDataPoints
            );
            processBuilder.directory(workingDirectory);
            // 合并错误流和输出流
            processBuilder.redirectErrorStream(true);
            // 启动进程
            Process process = processBuilder.start();
            // 读取脚本的输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            String lastLine = null;
            while ((line = reader.readLine()) != null) {
                lastLine = line;
                log.info(lastLine);
            }
            // 等待进程结束，并获取退出状态码
            int exitCode = process.waitFor();
            if (exitCode == 0 && lastLine.equals("success")) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("时空分析失败", e);
        }
    }

    public void preAction() {
        // 执行脚本
        File workingDirectory = new File(pythonPath);
        ProcessBuilder processBuilder = new ProcessBuilder(
                "pwd"
        );
        processBuilder.directory(workingDirectory);
        // 合并错误流和输出流
        processBuilder.redirectErrorStream(true);
        // 启动进程
        try {
            Process process = processBuilder.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            String lastLine = null;
            while ((line = reader.readLine()) != null) {
                lastLine = line;
                log.info(lastLine);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 序列数据插值算法
     * @param data
     * @return
     */
    public List<Float> linearInterpolate(List<Float> data) {
        List<Float> interpolatedData = new ArrayList<>(data);

        // 处理特殊情况
        if (interpolatedData == null || interpolatedData.isEmpty() || interpolatedData.stream().allMatch(Objects::isNull)) {
            return interpolatedData; // 返回空列表
        }

        // 处理边界情况 非空一定能找到一个值
        if (interpolatedData.get(0) == null) {
            int index = 1;
            while (index < interpolatedData.size() && interpolatedData.get(index) == null) {
                index++;
            }
            interpolatedData.set(0, interpolatedData.get(index));
        }

        if (interpolatedData.get(interpolatedData.size() - 1) == null) {
            int index = interpolatedData.size() - 2;
            while (index >= 0 && interpolatedData.get(index) == null) {
                index--;
            }
            interpolatedData.set(interpolatedData.size() - 1, interpolatedData.get(index));
        }

        // 插值处理 找前后两个非空值 一定可以找到
        for (int i = 1; i < interpolatedData.size() - 1; i++) {
            if (interpolatedData.get(i) == null) {
                int prevIndex = i - 1;
                while (prevIndex >= 0 && interpolatedData.get(prevIndex) == null) {
                    prevIndex--;
                }
                int nextIndex = i + 1;
                while (nextIndex < interpolatedData.size() && interpolatedData.get(nextIndex) == null) {
                    nextIndex++;
                }
                Float prevValue = interpolatedData.get(prevIndex);
                Float nextValue = interpolatedData.get(nextIndex);
                Float interpolatedValue = (prevValue + nextValue) / 2.0f;
                interpolatedData.set(i, interpolatedValue);
            }
        }
        return interpolatedData;
    }
}
